//********************************************************************************************************************//
//ORGANIZATION:
//AUTHOR: bpeng(bogers.peng@gmail.com)
//SUMMARY:
//********************************************************************************************************************//
#include "../String.h"
#include "../Exceptions.h"
#include "../Range.h"

using namespace Native::System;

bool ValidateLocation(const size_t& point, const CRange<size_t>& range)
{
    return range.InCloseRange(point);
}

CString::CString()
{
}

CString::CString(C_STRING& that) :
    CObject(that),
    _content(that._content)
{
}

CString::CString(C_STRING&& that) :
    CObject(that),
    _content(that._content)
{
}

CString::CString(WSTRING& content) :
    _content(content)
{
}

CString::CString(MSTRING& content) :
    _content(UString::ToWideString(content))
{
}

CString::CString(const wchar_t* content) :
    _content(content)
{
}

CString::~CString()
{
}

wstring CString::ToString() const
{
    return _content;
}

bool CString::operator==(C_STRING& rvalue) const
{
    return _content == rvalue._content;
}

bool CString::operator!=(C_STRING& rvalue) const
{
    return !operator==(rvalue);
}

bool CString::operator>(C_STRING& rvalue) const
{
    return _content > rvalue._content;
}

bool CString::operator<(C_STRING& rvalue) const
{
    return _content < rvalue._content;
}

bool CString::operator>=(C_STRING& rvalue) const
{
    return _content >= rvalue._content;
}

bool CString::operator<=(C_STRING& rvalue) const
{
    return _content <= rvalue._content;
}

bool CString::operator>(WSTRING& rvalue) const
{
    return _content > rvalue;
}

bool CString::operator<(WSTRING& rvalue) const
{
    return _content < rvalue;
}

bool CString::operator>=(WSTRING& rvalue) const
{
    return _content >= rvalue;
}

bool CString::operator<=(WSTRING& rvalue) const
{
    return _content <= rvalue;
}

bool CString::operator>(MSTRING& rvalue) const
{
    return UString::ToMultipleString(_content) > rvalue;
}

bool CString::operator<(MSTRING& rvalue) const
{
    return UString::ToMultipleString(_content) < rvalue;
}

bool CString::operator>=(MSTRING& rvalue) const
{
    return UString::ToMultipleString(_content) >= rvalue;
}

bool CString::operator<=(MSTRING& rvalue) const
{
    return UString::ToMultipleString(_content) <= rvalue;
}

size_t CString::Length() const
{
    return _content.length();
}

bool CString::Empty() const
{
    return _content.empty();
}

CString CString::Substring(size_t location, size_t length) const throw()
{
    COutOfRangeException<size_t>::Check(
        NATIVE_SCENE(L"Substring"),
        location,
        CRange<size_t>(0, _content.length()),
        ValidateLocation, L"location");

    if (END == length) {
        return _content.substr(location);
    } else {
        return (location + length <= _content.length())?
            _content.substr(location, length) : _content.substr(location);
    }
}

C_STRING& CString::Append(WSTRING& tail)
{
    _content.append(tail);

    return *this;
}

C_STRING& CString::Append(C_STRING& tail)
{
    _content.append(tail.ToString());

    return *this;
}

C_STRING& CString::Append(const wchar_t* tail)
{
    _content.append(tail);

    return *this;
}

C_STRING& CString::Append(wchar_t tail)
{
    _content.insert(_content.end(), tail);

    return *this;
}

vector<CString> CString::Split(wchar_t separator) const
{
    vector<CString> strings;
    wstring operation(_content);
    size_t index;

    if (!_content.empty()) {
        while ((index = operation.find(separator)) != -1) {
            strings.push_back(operation.substr(0, index));
            operation = operation.substr(index+1, _content.length());
        }

        strings.push_back(operation);
    }

    return move(strings);
}

CString CString::ToLower() const
{
    return UString::ToLower(_content);
}

CString CString::ToUpper() const
{
    return UString::ToUpper(_content);
}

CString CString::TrimLeft(wchar_t scrap) const
{
    wstring result;

    if (0 != _content.length()) {
        for (size_t i = 0; i < _content.length(); i++) {
            if (_content[i] != scrap) {
                result = _content.substr(i);

                break;
            }
        }
    }

    return result;
}

CString CString::TrimRight(wchar_t scrap) const
{
    wstring result;
    size_t length = _content.length();

    if (0 != length) {
        for (size_t i = length-1; i >= 0; i--) {
            if (_content[i] != scrap) {
                result = _content.substr(0, i+1);

                break;
            }
        }
    }

    return result;
}

CString CString::Trim(WSTRING& scraps) const
{
    CString result;

    for (int i = 0; i < scraps.size(); i++) {
        result = TrimLeft(scraps[i]).TrimRight(scraps[i]);
    }

    return move(result);
}

size_t CString::Find(C_STRING& keyword) const
{
    return _content.find(keyword.ToString());
}

size_t CString::FindFirst(C_STRING& keyword) const
{
    return Find(keyword);
}

wchar_t CString::Head() const
{
    return Empty()? 0 : _content[0];
}

wchar_t CString::Tail() const
{
    return Empty()? 0 : _content[_content.length()-1];
}

CWSTRING CString::ToCString() const
{
    return _content.c_str();
}

C_STRING& CString::operator=(C_STRING& rvalue)
{
    _content = rvalue._content;

    return *this;
}

wchar_t& CString::operator[](size_t index) throw()
{
    COutOfRangeException<size_t>::Check(
        NATIVE_SCENE(L"operator[]"),
        index, CRange<size_t>(0, _content.length()-1),
        ValidateLocation, L"index");

    return _content[index];
}

wchar_t CString::operator[](size_t index) const throw()
{
    COutOfRangeException<size_t>::Check(
        NATIVE_SCENE(L"operator[]"),
        index, CRange<size_t>(0, _content.length()-1),
        ValidateLocation, L"index");

    return _content[index];
}

bool CString::operator==(WSTRING& rvalue) const
{
    return _content == rvalue;
}

bool CString::operator==(MSTRING& rvalue) const
{
    return UString::ToMultipleString(_content) == rvalue;
}

bool CString::operator!=(WSTRING& rvalue) const
{
    return !operator==(rvalue);
}

bool CString::operator!=(MSTRING& rvalue) const
{
    return !operator==(rvalue);
}
//********************************************************************************************************************//
//CEmptyStringException
//********************************************************************************************************************//
void CEmptyStringException::Check(C_SCENE& scene, C_STRING& string, WSTRING& arguments, WSTRING& detail) throw()
{
    if (string.Empty()) {
        throw CEmptyStringException(scene, arguments, detail);
    }
}

CEmptyStringException::CEmptyStringException()
{
}

CEmptyStringException::CEmptyStringException(EMPTY_STRING_EXCEPTION& that)
    :CException(that)
{
}

CEmptyStringException::CEmptyStringException(EMPTY_STRING_EXCEPTION&& that)
    :CException(that)
{
}

CEmptyStringException::CEmptyStringException(C_SCENE& scene, WSTRING& arguments, WSTRING& detail)
{
    Append(CCase(scene, L"CString is empty", arguments, detail));
}